#include "httplib.hpp"

namespace httplib
{
    namespace detail
    {
        // 判断c是否为十六进制数字，是转换为int类型放到v里
        bool is_hex(char c, int &v)
        {
            // 0x20 <= c 排除控制字符
            if (0x20 <= c && isdigit(c))
            {
                v = c - '0';
                return true;
            }
            else if ('A' <= c && c <= 'F')
            {
                v = c - 'A' + 10;
                return true;
            }
            else if ('a' <= c && c <= 'f')
            {
                v = c - 'a' + 10;
                return true;
            }
            return false;
        }

        // 16进制转换10进制
        bool from_hex_to_i(const std::string &s, size_t i, size_t cnt, int &val)
        {
            if (i >= s.size())
            {
                return false;
            }

            val = 0;
            for (; cnt; i++, cnt--)
            {
                // 如果s[i] = 0 转换失败
                if (!s[i])
                {
                    return false;
                }
                auto v = 0;
                if (is_hex(s[i], v))
                {
                    val = val * 16 + v;
                }
                else
                {
                    return false;
                }
            }
            return true;
        }

        std::string from_i_to_hex(size_t n)
        {
            static const auto charset = "0123456789abcdef";
            std::string ret;
            do
            {
                // 15 -> 00001111
                ret = charset[n & 15] + ret;
                n >>= 4;
            } while (n > 0);
            return ret;
        }

        // Unicode码点 转换为 对应的 UTF-8编码
        size_t to_utf8(int code, char *buff)
        {
            if (code < 0x0080)
            {
                buff[0] = static_cast<char>(code & 0x7F);
                return 1;
            }
            else if (code < 0x0800)
            {
                buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
                buff[1] = static_cast<char>(0x80 | (code & 0x3F));
                return 2;
            }
            else if (code < 0xD800)
            {
                buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
                buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
                buff[2] = static_cast<char>(0x80 | (code & 0x3F));
                return 3;
            }
            else if (code < 0xE000)
            { // D800 - DFFF is invalid...
                return 0;
            }
            else if (code < 0x10000)
            {
                buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
                buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
                buff[2] = static_cast<char>(0x80 | (code & 0x3F));
                return 3;
            }
            else if (code < 0x110000)
            {
                buff[0] = static_cast<char>(0xF0 | ((code >> 18) & 0x7));
                buff[1] = static_cast<char>(0x80 | ((code >> 12) & 0x3F));
                buff[2] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
                buff[3] = static_cast<char>(0x80 | (code & 0x3F));
                return 4;
            }

            // NOTREACHED
            return 0;
        }

        // 实现Base64编码的函数 用于将输入字符串进行Base64编码
        // Base64编码可以确保URL中不包含可能与URL语法冲突的字符，从而防止URL解析错误。
        std::string base64_encode(const std::string &in)
        {
            static const auto lookup =
                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

            std::string out;
            out.reserve(in.size());

            auto val = 0;
            auto valb = -6;

            for (auto c : in)
            {
                val = (val << 8) + static_cast<uint8_t>(c);
                valb += 8;
                while (valb >= 0)
                {
                    out.push_back(lookup[(val >> valb) & 0x3F]);
                    valb -= 6;
                }
            }

            if (valb > -6)
            {
                out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]);
            }

            while (out.size() % 4)
            {
                out.push_back('=');
            }

            return out;
        }

        bool is_file(const std::string &path)
        {
            struct stat st;
            // 1 stat() >0表示读取成功，-1表示读取失败
            // 2 S_ISREG(st.st_mode) 宏检查文件是否是普通文件而不是 设备文件、目录、其他文件
            return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
        }

        bool is_dir(const std::string &path)
        {
            struct stat st;
            // S_ISDIR 检查是否为目录
            return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
        }

        // 判断根部是否是有效的
        // 遇到非法目录减小路径级别，防止对系统的文件系统非法访问
        // 遇到正常目录则可以进入
        bool is_valid_path(const std::string &path)
        {
            size_t level = 0;
            size_t i = 0;

            // 跳过开头的/
            while (i < path.size() && path[i] == '/')
            {
                i++;
            }

            while (i < path.size())
            {
                // Read component
                auto beg = i;
                while (i < path.size() && path[i] != '/')
                {
                    i++;
                }

                auto len = i - beg;
                assert(len > 0);

                if (!path.compare(beg, len, "."))
                {
                    ;
                }
                else if (!path.compare(beg, len, ".."))
                {
                    if (level == 0)
                    {
                        return false;
                    }
                    level--;
                }
                else
                {
                    level++;
                }

                // Skip slash
                while (i < path.size() && path[i] == '/')
                {
                    i++;
                }
            }

            return true;
        }

        std::string encode_query_param(const std::string &value)
        {
            std::ostringstream escaped;
            escaped.fill('0');
            escaped << std::hex;

            for (auto c : value)
            {
                if (std::isalnum(static_cast<uint8_t>(c)) || c == '-' || c == '_' ||
                    c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' ||
                    c == ')')
                {
                    escaped << c;
                }
                else
                {
                    escaped << std::uppercase;
                    escaped << '%' << std::setw(2)
                            << static_cast<int>(static_cast<unsigned char>(c));
                    escaped << std::nouppercase;
                }
            }

            return escaped.str();
        }

        // URL编码
        std::string encode_url(const std::string &s)
        {
            std::string result;
            result.reserve(s.size());

            for (size_t i = 0; s[i]; i++)
            {
                switch (s[i])
                {
                case ' ':
                    result += "%20";
                    break;
                case '+':
                    result += "%2B";
                    break;
                case '\r':
                    result += "%0D";
                    break;
                case '\n':
                    result += "%0A";
                    break;
                case '\'':
                    result += "%27";
                    break;
                case ',':
                    result += "%2C";
                    break;
                // case ':': result += "%3A"; break; // ok? probably...
                case ';':
                    result += "%3B";
                    break;
                default:
                    auto c = static_cast<uint8_t>(s[i]);
                    if (c >= 0x80)
                    {
                        result += '%';
                        char hex[4];
                        auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c);
                        assert(len == 2);
                        result.append(hex, static_cast<size_t>(len));
                    }
                    else
                    {
                        result += s[i];
                    }
                    break;
                }
            }

            return result;
        }

        // URL解码
        std::string decode_url(const std::string &s,
                               bool convert_plus_to_space)
        {
            std::string result;

            for (size_t i = 0; i < s.size(); i++)
            {
                if (s[i] == '%' && i + 1 < s.size())
                {
                    if (s[i + 1] == 'u')
                    {
                        auto val = 0;
                        if (from_hex_to_i(s, i + 2, 4, val))
                        {
                            // 4 digits Unicode codes
                            char buff[4];
                            size_t len = to_utf8(val, buff);
                            if (len > 0)
                            {
                                result.append(buff, len);
                            }
                            i += 5; // 'u0000'
                        }
                        else
                        {
                            result += s[i];
                        }
                    }
                    else
                    {
                        auto val = 0;
                        if (from_hex_to_i(s, i + 1, 2, val))
                        {
                            // 2 digits hex codes
                            result += static_cast<char>(val);
                            i += 2; // '00'
                        }
                        else
                        {
                            result += s[i];
                        }
                    }
                }
                else if (convert_plus_to_space && s[i] == '+')
                {
                    result += ' ';
                }
                else
                {
                    result += s[i];
                }
            }

            return result;
        }

        void read_file(const std::string &path, std::string &out)
        {
            std::ifstream fs(path, std::ios_base::binary);
            fs.seekg(0, std::ios_base::end);
            auto size = fs.tellg();
            fs.seekg(0);
            out.resize(static_cast<size_t>(size));
            fs.read(&out[0], static_cast<std::streamsize>(size));
        }

        std::string file_extension(const std::string &path)
        {
            std::smatch m;
            static auto re = std::regex("\\.([a-zA-Z0-9]+)$");
            if (std::regex_search(path, m, re))
            {
                return m[1].str();
            }
            return std::string();
        }

        bool has_header(const Headers &headers, const std::string &key)
        {
            return headers.find(key) != headers.end();
        }

        const char *get_header_value(const Headers &headers,
                                     const std::string &key, size_t id,
                                     const char *def)
        {
            auto rng = headers.equal_range(key); // rng是一个范围，包括第一次和最后一次出现的位置
            auto it = rng.first;
            std::advance(it, static_cast<ssize_t>(id)); // advance ->移动 必须转成ssize_t类型
            if (it != rng.second)
            {
                // 找到返回对应的值
                return it->second.c_str();
            }

            return def;
        }

        inline uint64_t get_header_value_u64(const Headers &headers,
                                             const std::string &key, size_t id,
                                             uint64_t def)
        {
            auto rng = headers.equal_range(key);
            auto it = rng.first;
            std::advance(it, static_cast<ssize_t>(id));
            if (it != rng.second)
            {
                // strtoull 将字符串转换为无符号长整型
                return std::strtoull(it->second.data(), nullptr, 10);
            }
            return def;
        }

        bool has_crlf(const std::string s)
        {
            const char *p = s.c_str();
            while (*p)
            {
                if (*p == '\r' || *p == '\n')
                {
                    return true;
                }
                p++;
            }

            return false;
        }

        class ContentProviderAdapter
        {
        public:
            // 右值引用，对于大的内容提供者可以提高效率
            explicit ContentProviderAdapter(
                ContentProviderWithoutLength &&content_provider)
                : content_provider_(content_provider) {}

            // 对()重载，使得ContentProviderWithoutLength
            // 能使得ContentProviderAdapter可以赋值给ContentProvider（function<>）
            bool operator()(size_t offset, size_t, DataSink &sink)
            {
                return content_provider_(offset, sink);
            }

        private:
            ContentProviderWithoutLength content_provider_;
        };

    } // namespace detail

    // Request implementation
    bool Request::has_header(const std::string &key) const
    {
        return detail::has_header(headers, key);
    }

    std::string Request::get_header_value(const std::string &key, size_t id) const
    {
        return detail::get_header_value(headers, key, id, "");
    }

    uint64_t Request::get_header_value_u64(const std::string &key, size_t id = 0) const
    {
        return detail::get_header_value_u64(headers, key, id, 0);
    }

    size_t Request::get_header_value_count(const std::string &key) const
    {
        // 高效的求请求头的数量
        auto range = headers.equal_range(key);
        return static_cast<size_t>(std::distance(range.first, range.second));
    }

    void Request::set_header(const std::string &key, const std::string &val)
    {
        if (!detail::has_crlf(key) && !detail::has_crlf(val))
        {
            headers.emplace(key, val);
        }
    }

    bool Request::has_param(const std::string &key) const
    {
        return params.find(key) != params.end();
    }

    std::string Request::get_param_value(const std::string &key, size_t id = 0) const
    {
        auto rng = params.equal_range(key);
        auto it = rng.first;
        std::advance(it, static_cast<ssize_t>(id));
        if (it != rng.second)
        {
            return it->second;
        }
        return std::string();
    }

    size_t Request::get_param_value_count(const std::string &key) const
    {
        auto rng = params.equal_range(key);
        return static_cast<size_t>(std::distance(rng.first, rng.second));
    }

    // BUG 与参考不同
    bool Request::is_multipart_form_data() const
    {
        const auto &content_type = get_header_value("Content-Type");
        return content_type.find("multipart/form-data", 0);
    }

    bool Request::has_file(const std::string &key) const
    {
        return files.find(key) != files.end();
    }

    MultipartFormData Request::get_file_value(const std::string &key) const
    {
        auto it = files.find(key);
        if (it != files.end())
        {
            return it->second;
        }

        return MultipartFormData();
    }

    // key指的是表单中的属性名
    std::vector<MultipartFormData> Request::get_file_values(const std::string &key) const
    {
        std::vector<MultipartFormData> values;
        auto rng = files.equal_range(key);
        for (auto it = rng.first; it != rng.second; it++)
        {
            values.push_back(it->second);
        }
        return values;
    }

    // Response implementation

    bool Response::has_header(const std::string &key) const
    {
        return headers.find(key) != headers.end();
    }

    std::string Response::get_header_value(const std::string &key,
                                           size_t id) const
    {
        return detail::get_header_value(headers, key, id, "");
    }

    size_t Response::get_header_value_count(const std::string &key) const
    {
        auto r = headers.equal_range(key);
        return static_cast<size_t>(std::distance(r.first, r.second));
    }

    void Response::set_header(const std::string &key,
                              const std::string &val)
    {
        if (!detail::has_crlf(key) && !detail::has_crlf(val))
        {
            headers.emplace(key, val);
        }
    }

    void Response::set_redirect(const std::string &url, int stat)
    {
        if (!detail::has_crlf(url))
        {
            set_header("Location", url);

            if (300 <= stat && stat < 400)
            {
                this->status = stat;
            }
            else
            {
                // 通知客户端资源已被临时移动到新的位置。
                this->status = StatusCode::Found_302;
            }
        }
    }

    // 设置body内容，更新/设置 Content-Type 头
    void Response::set_content(const char *s, size_t n,
                               const std::string &content_type)
    {
        body.assign(s, n);

        auto rng = headers.equal_range("Content-Type");
        headers.erase(rng.first, rng.second);

        set_header("Content-Type", content_type);
    }

    void Response::set_content(const std::string &s,
                               const std::string &content_type)
    {
        set_content(s.data(), s.size(), content_type);
    }

    void Response::set_content_provider(
        size_t in_length, const std::string &content_type, ContentProvider provider,
        ContentProviderResourceReleaser resource_releaser)
    {
        set_header("Content-Type", content_type);
        content_length_ = in_length;
        if (in_length > 0)
        {
            content_provider_ = std::move(provider);
        }
        content_provider_resource_releaser_ = resource_releaser;
        is_chunked_content_provider_ = false;
    }

    // 设置一个HTTP响应的内容提供者，包括MIME类型、数据提供方式以及如何处理响应结束后的资源释放。
    void Response::set_content_provider(
        const std::string &content_type, ContentProviderWithoutLength provider,
        ContentProviderResourceReleaser resource_releaser)
    {
        // 虽然内容提供者负责提供数据，但是设置HTTP头是一个独立的行为
        // 它属于HTTP响应的构建过程。内容提供者可能不知道或者不关心数据的具体MIME类型
        // 它只是负责返回数据。
        set_header("Content-Type", content_type);
        content_length_ = 0;

        // 避免不必要的拷贝，provider可能很大
        content_provider_ = detail::ContentProviderAdapter(std::move(provider));
        content_provider_resource_releaser_ = resource_releaser;
        is_chunked_content_provider_ = false;
    }

    // 分块传输
    void Response::set_chunked_content_provider(
        const std::string &content_type, ContentProviderWithoutLength provider,
        ContentProviderResourceReleaser resource_releaser)
    {
        set_header("Content-Type", content_type);
        content_length_ = 0;
        content_provider_ = detail::ContentProviderAdapter(std::move(provider));
        content_provider_resource_releaser_ = resource_releaser;
        is_chunked_content_provider_ = true;
    }

    // server impletation
    Server::Server()
        : new_task_queue([]
                         { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); })
    {
    }

    Server::~Server() = default;

    std::unique_ptr<detail::MatcherBase>
    Server::make_matcher(const std::string &pattern)
    {
        if (pattern.find("/:") != std::string::npos)
        {
            // 路径参数匹配
            return detail::make_unique<detail::PathParamsMatcher>(pattern);
        }
        else
        {
            // 正则匹配
            return detail::make_unique<detail::RegexMatcher>(pattern);
        }
    }

    Server &Server::Get(const std::string &pattern, Handler handler)
    {
        get_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
        return *this;
    }

    Server &Server::Post(const std::string &pattern, Handler handler)
    {
        post_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
        return *this;
    }

    Server &Server::Post(const std::string &pattern,
                         HandlerWithContentReader handler)
    {
        post_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
                                                       std::move(handler));
        return *this;
    }

    Server &Server::Put(const std::string &pattern, Handler handler)
    {
        put_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
        return *this;
    }

    Server &Server::Put(const std::string &pattern,
                        HandlerWithContentReader handler)
    {
        put_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
                                                      std::move(handler));
        return *this;
    }

    Server &Server::Patch(const std::string &pattern, Handler handler)
    {
        patch_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
        return *this;
    }

    Server &Server::Patch(const std::string &pattern,
                          HandlerWithContentReader handler)
    {
        patch_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
                                                        std::move(handler));
        return *this;
    }

    Server &Server::Delete(const std::string &pattern, Handler handler)
    {
        delete_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
        return *this;
    }

    Server &Server::Delete(const std::string &pattern,
                           HandlerWithContentReader handler)
    {
        delete_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
                                                         std::move(handler));
        return *this;
    }

    Server &Server::Options(const std::string &pattern, Handler handler)
    {
        options_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
        return *this;
    }

    bool Server::set_base_dir(const std::string &dir,
                              const std::string &mount_point)
    {
        return set_mount_point(mount_point, dir);
    }

    bool Server::set_mount_point(const std::string &mount_point,
                                 const std::string &dir, Headers headers)
    {
        if (detail::is_dir(dir))
        {
            std::string mnt = !mount_point.empty() ? mount_point : "/";
            if (!mnt.empty() && mnt[0] == '/')
            {
                base_dirs_.push_back({mnt, dir, std::move(headers)});
                return true;
            }
        }
        return false;
    }

    bool Server::remove_mount_point(const std::string &mount_point)
    {
        for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it)
        {
            if (it->mount_point == mount_point)
            {
                base_dirs_.erase(it);
                return true;
            }
        }
        return false;
    }

}